
<!DOCTYPE html
  PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   
      <title>15.3.&nbsp;重构</title>
      <link rel="stylesheet" href="../diveintopython.css" type="text/css">
      <link rev="made" href="mailto:f8dy@diveintopython.org">
      <meta name="generator" content="DocBook XSL Stylesheets V1.52.2">
      <meta name="keywords" content="Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free">
      <meta name="description" content="Python from novice to pro">
      <link rel="home" href="../toc/index.html" title="Dive Into Python">
      <link rel="up" href="index.html" title="第&nbsp;15&nbsp;章&nbsp;重构">
      <link rel="previous" href="handling_changing_requirements.html" title="15.2.&nbsp;应对需求变化">
      <link rel="next" href="postscript.html" title="15.4.&nbsp;后记">
   </head>
   <body>
      <table id="Header" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
         <tr>
            <td id="breadcrumb" colspan="5" align="left" valign="top">导航：<a href="../index.html">起始页</a>&nbsp;&gt;&nbsp;<a href="../toc/index.html">Dive Into Python</a>&nbsp;&gt;&nbsp;<a href="index.html">重构</a>&nbsp;&gt;&nbsp;<span class="thispage">重构</span></td>
            <td id="navigation" align="right" valign="top">&nbsp;&nbsp;&nbsp;<a href="handling_changing_requirements.html" title="上一页: “应对需求变化”">&lt;&lt;</a>&nbsp;&nbsp;&nbsp;<a href="postscript.html" title="下一页: “后记”">&gt;&gt;</a></td>
         </tr>
         <tr>
            <td colspan="3" id="logocontainer">
               <h1 id="logo"><a href="../index.html" accesskey="1">深入 Python :Dive Into Python 中文版</a></h1>
               <p id="tagline">Python 从新手到专家 [Dip_5.4b_CPyUG_Release]</p>
            </td>
            <td colspan="3" align="right">
               <form id="search" method="GET" action="http://www.google.com/custom">
                  <p><label for="q" accesskey="4">Find:&nbsp;</label><input type="text" id="q" name="q" size="20" maxlength="255" value=""> <input type="submit" value="搜索"><input type="hidden" name="domains" value="woodpecker.org.cn/diveintopython"><input type="hidden" name="sitesearch" value="www.woodpecker.org.cn/diveintopython"></p>
               </form>
            </td>
         </tr>
      </table>
      <!--#include virtual="/inc/ads" -->
      <div class="section" lang="zh_cn">
         <div class="titlepage">
            <div>
               <div>
                  <h2 class="title"><a name="roman.refactoring"></a>15.3.&nbsp;重构
                  </h2>
               </div>
            </div>
            <div></div>
         </div>
         <div class="abstract">
            <p>全面的单元测试带来的最大好处不是你的全部测试用例最终通过时的成就感；也不是被责怪破坏了别人的代码时能够<span class="emphasis"><em>证明</em></span> 自己的自信。最大的好处是单元测试给了你自由去无情地重构。
            </p>
         </div>
         <p>重构是在可运行代码的基础上使之工作得更好的过程。通常，“<span class="quote">更好</span>”意味着“<span class="quote">更快</span>”，也可能意味着 “<span class="quote">使用更少的内存</span>”，或者 “<span class="quote">使用更少的磁盘空间</span>”，或者仅仅是“<span class="quote">更优雅的代码</span>”。不管对你，对你的项目意味什么，在你的环境中，重构对任何程序的长期良性运转都是重要的。
         </p>
         <p>这里，“<span class="quote">更好</span>” 意味着 “<span class="quote">更快</span>”。更具体地说，<tt class="function">fromRoman</tt> 函数可以更快，关键在于那个丑陋的、用于验证罗马数字有效性的正则表达式。尝试不用正则表达式去解决是不值得的 (这样做很难，而且可能也快不了多少)，但可以通过预编译正则表达式使函数提速。
         </p>
         <div class="example"><a name="d0e34816"></a><h3 class="title">例&nbsp;15.10.&nbsp;编译正则表达式</h3><pre class="screen">
<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput"><span class='pykeyword'>import</span> re</span>
<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">pattern = <span class='pystring'>'^M?M?M?$'</span></span>
<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">re.search(pattern, <span class='pystring'>'M'</span>)</span>               <a name="roman.refactoring.1.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
<span class="computeroutput">&lt;SRE_Match object at 01090490&gt;</span>
<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">compiledPattern = re.compile(pattern)</span> <a name="roman.refactoring.1.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">compiledPattern</span>
<span class="computeroutput">&lt;SRE_Pattern object at 00F06E28&gt;</span>
<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">dir(compiledPattern)</span>                  <a name="roman.refactoring.1.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12">
<span class="computeroutput">['findall', 'match', 'scanner', 'search', 'split', 'sub', 'subn']</span>
<tt class="prompt">&gt;&gt;&gt; </tt><span class="userinput">compiledPattern.search(<span class='pystring'>'M'</span>)</span>           <a name="roman.refactoring.1.4"></a><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12">
<span class="computeroutput">&lt;SRE_Match object at 01104928&gt;</span></pre><div class="calloutlist">
               <table border="0" summary="Callout list">
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.1.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">这是你看到过的 <tt class="function">re.search</tt> 语法。把一个正则表达式作为字符串 (<tt class="varname">pattern</tt>) 并用这个字符串来匹配 (<tt class="literal">'M'</tt>)。如果能够匹配，函数返回 一个 match 对象，可以用来确定匹配的部分和如何匹配的。
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.1.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">这里是一个新的语法：<tt class="function">re.compile</tt> 把一个正则表达式作为字符串参数接受并返回一个 pattern 对象。注意这里没去匹配字符串。编译正则表达式和以特定字符串 (<tt class="literal">'M'</tt>) 进行匹配不是一回事，所牵扯的只是正则表达式本身。
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.1.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left"><tt class="function">re.compile</tt> 返回的已编译的 pattern 对象有几个值得关注的功能：包括了几个 <tt class="filename">re</tt> 模块直接提供的功能 (比如：<tt class="function">search</tt> 和 <tt class="function">sub</tt>)。
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.1.4"><img src="../images/callouts/4.png" alt="4" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">用 <tt class="literal">'M'</tt> 作参数来调用已编译的 pattern 对象的 <tt class="function">search</tt> 函数与用正则表达式和字符串 <tt class="literal">'M'</tt> 调用 <tt class="function">re.search</tt> 可以得到相同的结果，只是快了很多。 (事实上，<tt class="function">re.search</tt> 函数仅仅将正则表达式编译，然后为你调用编译后的 pattern 对象的 <tt class="function">search</tt> 方法。)
                     </td>
                  </tr>
               </table>
            </div>
         </div><a name="d0e34932"></a><table class="note" border="0" summary="">
            <tr>
               <td rowspan="2" align="center" valign="top" width="1%"><img src="../images/note.png" alt="注意" title="" width="24" height="24"></td>
            </tr>
            <tr>
               <td colspan="2" align="left" valign="top" width="99%">在需要多次使用同一个正则表达式的情况下，应该将它进行编译以获得一个 pattern 对象，然后直接调用这个 pattern 对象的方法。</td>
            </tr>
         </table>
         <div class="example"><a name="d0e34937"></a><h3 class="title">例&nbsp;15.11.&nbsp;<tt class="filename">roman81.py</tt> 中已编译的正则表达式
            </h3>
            <p>这个文件可以在例子目录下的 <tt class="filename">py/roman/stage8/</tt> 目录中找到。
            </p>
            <p>如果您还没有下载本书附带的样例程序, 可以 <a href="http://www.woodpecker.org.cn/diveintopython/download/diveintopython-exampleszh-cn-5.4b.zip" title="Download example scripts">下载本程序和其他样例程序</a>。
            </p><pre class="programlisting">
<span class='pycomment'># toRoman and rest of module omitted for clarity</span>

romanNumeralPattern = \
    re.compile(<span class='pystring'>'^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$'</span>) <a name="roman.refactoring.2.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">

<span class='pykeyword'>def</span><span class='pyclass'> fromRoman</span>(s):
    <span class='pystring'>"""convert Roman numeral to integer"""</span>
    <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> s:
        <span class='pykeyword'>raise</span> InvalidRomanNumeralError, <span class='pystring'>'Input can not be blank'</span>
    <span class='pykeyword'>if</span> <span class='pykeyword'>not</span> romanNumeralPattern.search(s):                                    <a name="roman.refactoring.2.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12">
        <span class='pykeyword'>raise</span> InvalidRomanNumeralError, <span class='pystring'>'Invalid Roman numeral: %s'</span> % s

    result = 0
    index = 0
    <span class='pykeyword'>for</span> numeral, integer <span class='pykeyword'>in</span> romanNumeralMap:
        <span class='pykeyword'>while</span> s[index:index+len(numeral)] == numeral:
            result += integer
            index += len(numeral)
    <span class='pykeyword'>return</span> result
</pre><div class="calloutlist">
               <table border="0" summary="Callout list">
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.2.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">看起来很相似，但实质却有很大改变。<tt class="varname">romanNumeralPattern</tt> 不再是一个字符串了，而是一个由 <tt class="function">re.compile</tt> 返回的 pattern 对象。
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.2.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">这意味着你可以直接调用 <tt class="varname">romanNumeralPattern</tt> 的方法。这比每次调用 <tt class="function">re.search</tt> 要快很多。模块被首次导入 (import) 之时，正则表达式被一次编译并存储于 <tt class="varname">romanNumeralPattern</tt>。之后每次调用 <tt class="function">fromRoman</tt> 时，你可以立刻以正则表达式匹配输入的字符串，而不需要在重复背后的这些编译的工作。
                     </td>
                  </tr>
               </table>
            </div>
         </div>
         <p>那么编译正则表达式可以提速多少呢？你自己来看吧：</p>
         <div class="example"><a name="roman.stage8.1.output"></a><h3 class="title">例&nbsp;15.12.&nbsp;用 <tt class="filename">romantest81.py</tt> 测试 <tt class="filename">roman81.py</tt> 的结果
            </h3><pre class="screen"><span class="computeroutput">.............          </span><a name="roman.refactoring.3.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">
----------------------------------------------------------------------
Ran 13 tests in 3.385s </span><a name="roman.refactoring.3.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"><span class="computeroutput">

OK</span>                     <a name="roman.refactoring.3.3"></a><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></pre><div class="calloutlist">
               <table border="0" summary="Callout list">
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.3.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">有一点说明一下：这里，我在运行单元测试时<span class="emphasis"><em>没有</em></span> 使用 <tt class="option">-v</tt> 选项，因此输出的也不再是每个测试完整的 <tt class="literal">doc string</tt>，而是用一个圆点来表示每个通过的测试。(失败的测试标用 <tt class="literal">F</tt> 表示，发生错误则用 <tt class="literal">E</tt> 表示，你仍旧可以获得失败和错误的完整追踪信息以便查找问题所在。)
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.3.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">运行 <tt class="literal">13</tt> 个测试耗时 <tt class="literal">3.385</tt> 秒，与之相比是没有预编译正则表达式时的 <tt class="literal">3.685秒</tt>。这是一个 <tt class="literal">8%</tt> 的整体提速，记住单元测试的大量时间实际上花在做其他工作上。(我单独测试了正则表达式部分的耗时，不考虑单元测试的其他环节，正则表达式编译可以让匹配 <tt class="function">search</tt> 平均提速 <tt class="literal">54%</tt>。)小小修改还真是值得。
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.3.3"><img src="../images/callouts/3.png" alt="3" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">对了，不必顾虑什么，预先编译正则表达式并没有破坏什么，你刚刚证实这一点。</td>
                  </tr>
               </table>
            </div>
         </div>
         <p>我还想做另外一个性能优化工作。就正则表达式语法的复杂性而言，通常有不止一种方法来构造相同的表达式是不会令人惊讶的。在 <a href="http://groups.google.com/groups?group=comp.lang.python">comp.lang.python</a> 上对该模块进行一些讨论后，有人建议我使用 <tt class="literal">{<i class="replaceable">m</i>,<i class="replaceable">n</i>}</tt> 语法来查找可选重复字符。
         </p>
         <div class="example"><a name="d0e35062"></a><h3 class="title">例&nbsp;15.13.&nbsp;<tt class="filename">roman82.py</tt></h3>
            <p>这个文件可以在例子目录下的 <tt class="filename">py/roman/stage8/</tt> 目录中找到。
            </p>
            <p>如果您还没有下载本书附带的样例程序, 可以 <a href="http://www.woodpecker.org.cn/diveintopython/download/diveintopython-exampleszh-cn-5.4b.zip" title="Download example scripts">下载本程序和其他样例程序</a>。
            </p><pre class="programlisting">
<span class='pycomment'># rest of program omitted for clarity</span>

<span class='pycomment'>#old version</span>
<span class='pycomment'>#romanNumeralPattern = \</span>
<span class='pycomment'>#   re.compile('^M?M?M?M?(CM|CD|D?C?C?C?)(XC|XL|L?X?X?X?)(IX|IV|V?I?I?I?)$')</span>

<span class='pycomment'>#new version</span>
romanNumeralPattern = \
    re.compile(<span class='pystring'>'^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'</span>) <a name="roman.refactoring.4.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
</pre><div class="calloutlist">
               <table border="0" summary="Callout list">
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.4.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">你已经将 <tt class="literal">M?M?M?M?</tt> 替换为 <tt class="literal">M{0,4}</tt>。它们的含义相同：“<span class="quote">匹配 0 到 4 个 <tt class="literal">M</tt> 字符</span>”。类似地，<tt class="literal">C?C?C?</tt> 改成了 <tt class="literal">C{0,3}</tt> (“<span class="quote">匹配 0 到 3 个 <tt class="literal">C</tt> 字符</span>”) 接下来的 <tt class="literal">X</tt> 和 <tt class="literal">I</tt> 也一样。
                     </td>
                  </tr>
               </table>
            </div>
         </div>
         <p>这样的正则表达简短一些 (虽然可读性不太好)。核心问题是，是否能加快速度？</p>
         <div class="example"><a name="d0e35116"></a><h3 class="title">例&nbsp;15.14.&nbsp;以 <tt class="filename">romantest82.py</tt> 测试 <tt class="filename">roman82.py</tt> 的结果
            </h3><pre class="screen"><span class="computeroutput">.............
----------------------------------------------------------------------
Ran 13 tests in 3.315s </span><a name="roman.refactoring.5.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">

OK</span>                     <a name="roman.refactoring.5.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></pre><div class="calloutlist">
               <table border="0" summary="Callout list">
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.5.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">总体而言，这种正则表达使单元测试提速 2%。这不太令人振奋，但记住 <tt class="function">search</tt> 函数只是整体单元测试的一个小部分，很多时间花在了其他方面。(我另外的测试表明这个应用了新语法的正则表达式使 <tt class="function">search</tt> 函数提速 <tt class="literal">11%</tt> 。) 通过预先编译和使用新语法重写可以使正则表达式的性能提升超过 <tt class="literal">60%</tt>，令单元测试的整体性能提升超过 <tt class="literal">10%</tt>。
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.5.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">比任何的性能提升更重要的是模块仍然运转完好。这便是我早先提到的自由：自由地调整、修改或者重写任何部分并且保证在此过程中没有把事情搞得一团糟。这并不是给无休止地为了调整代码而调整代码以许可；你有很切实的目标 (“<span class="quote">让 <tt class="function">fromRoman</tt> 更快</span>”)，而且你可以实现这个目标，不会因为考虑在改动过程中是否会引入新的 Bug 而有所迟疑。
                     </td>
                  </tr>
               </table>
            </div>
         </div>
         <p>还有另外一个我想做的调整，我保证这是最后一个，之后我会停下来，让这个模块歇歇。就像你多次看到的，正则表达式越晦涩难懂越快，我可不想在六个月内再回头试图维护它。是呀！测试用例通过了，我便知道它工作正常，但如果我搞不懂它是<span class="emphasis"><em>如何</em></span> 工作的，添加新功能、修正新 Bug，或者维护它都将变得很困难。正如你在 <a href="../regular_expressions/verbose.html" title="7.5.&nbsp;松散正则表达式">第&nbsp;7.5&nbsp;节 “松散正则表达式”</a> 看到的，<span class="application">Python</span> 提供了逐行注释你的逻辑的方法。
         </p>
         <div class="example"><a name="d0e35171"></a><h3 class="title">例&nbsp;15.15.&nbsp;<tt class="filename">roman83.py</tt></h3>
            <p>该文件可以在例子目录下的 <tt class="filename">py/roman/stage8/</tt> 目录中找到。
            </p>
            <p>如果您还没有下载本书附带的样例程序, 可以 <a href="http://www.woodpecker.org.cn/diveintopython/download/diveintopython-exampleszh-cn-5.4b.zip" title="Download example scripts">下载本程序和其他样例程序</a>。
            </p><pre class="programlisting">
<span class='pycomment'># rest of program omitted for clarity</span>

<span class='pycomment'>#old version</span>
<span class='pycomment'>#romanNumeralPattern = \</span>
<span class='pycomment'>#   re.compile('^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$')</span>

<span class='pycomment'>#new version</span>
romanNumeralPattern = re.compile(<span class='pystring'>'''
    ^                   # beginning of string
    M{0,4}              # thousands - 0 to 4 M's
    (CM|CD|D?C{0,3})    # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
                        #            or 500-800 (D, followed by 0 to 3 C's)
    (XC|XL|L?X{0,3})    # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
                        #        or 50-80 (L, followed by 0 to 3 X's)
    (IX|IV|V?I{0,3})    # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
                        #        or 5-8 (V, followed by 0 to 3 I's)
    $                   # end of string
    '''</span>, re.VERBOSE) <a name="roman.refactoring.6.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12">
</pre><div class="calloutlist">
               <table border="0" summary="Callout list">
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.6.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left"><tt class="function">re.compile</tt> 函数的第二个参数是可选的，这个参数通过一个或一组标志 (flag) 来控制预编译正则表达式的选项。这里你指定了 <tt class="literal">re.VERBOSE</tt> 选项，告诉 <span class="application">Python</span> 正则表达式里有内联注释。注释和它们周围的空白<span class="emphasis"><em>不</em></span> 会被认做正则表达式的一部分，在编译正则表达式时 <tt class="function">re.compile</tt> 函数会忽略它们。这个新 “<span class="quote">verbose</span>” 版本与老版本完全一样，只是更具可读性。
                     </td>
                  </tr>
               </table>
            </div>
         </div>
         <div class="example"><a name="d0e35210"></a><h3 class="title">例&nbsp;15.16.&nbsp;用 <tt class="filename">romantest83.py</tt> 测试 <tt class="filename">roman83.py</tt> 的结果
            </h3><pre class="screen"><span class="computeroutput">.............
----------------------------------------------------------------------
Ran 13 tests in 3.315s </span><a name="roman.refactoring.7.1"></a><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"><span class="computeroutput">

OK</span>                     <a name="roman.refactoring.7.2"></a><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></pre><div class="calloutlist">
               <table border="0" summary="Callout list">
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.7.1"><img src="../images/callouts/1.png" alt="1" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">新 “<span class="quote">verbose</span>” 版本和老版本的运行速度一样。事实上，编译的 pattern 对象也一样，因为 <tt class="function">re.compile</tt> 函数会剔除掉所有你添加的内容。
                     </td>
                  </tr>
                  <tr>
                     <td width="12" valign="top" align="left"><a href="#roman.refactoring.7.2"><img src="../images/callouts/2.png" alt="2" border="0" width="12" height="12"></a> 
                     </td>
                     <td valign="top" align="left">新 “<span class="quote">verbose</span>” 版本可以通过所有老版本通过的测试。什么都没有改变，但在六个月后重读该模块的程序员却有了理解功能如何实现的机会。
                     </td>
                  </tr>
               </table>
            </div>
         </div>
      </div>
      <table class="Footer" width="100%" border="0" cellpadding="0" cellspacing="0" summary="">
         <tr>
            <td width="35%" align="left"><br><a class="NavigationArrow" href="handling_changing_requirements.html">&lt;&lt;&nbsp;应对需求变化</a></td>
            <td width="30%" align="center"><br>&nbsp;<span class="divider">|</span>&nbsp;<a href="index.html#roman.bugs" title="15.1.&nbsp;处理 bugs">1</a> <span class="divider">|</span> <a href="handling_changing_requirements.html" title="15.2.&nbsp;应对需求变化">2</a> <span class="divider">|</span> <span class="thispage">3</span> <span class="divider">|</span> <a href="postscript.html" title="15.4.&nbsp;后记">4</a> <span class="divider">|</span> <a href="summary.html" title="15.5.&nbsp;小结">5</a>&nbsp;<span class="divider">|</span>&nbsp;
            </td>
            <td width="35%" align="right"><br><a class="NavigationArrow" href="postscript.html">后记&nbsp;&gt;&gt;</a></td>
         </tr>
         <tr>
            <td colspan="3"><br></td>
         </tr>
      </table>
      <div class="Footer">
         <p class="copyright">Copyright © 2000, 2001, 2002, 2003, 2004 <a href="mailto:mark@diveintopython.org">Mark Pilgrim</a></p>
         <p class="copyright">Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007 <a href="mailto:python-cn@googlegroups.com">CPyUG (邮件列表)</a></p>
      </div>
   </body>
</html>